/************************************************************************/
/*                                                                      */
/*  This file is a part of the example programs from the paper:         */
/*                                                                      */
/*  K. Czarnecki and Ulrich Eisenecker.                                 */
/*  Components and Generative Programming.                              */
/*  Invited talk, in Proceedings of the Joint European                  */
/*  Software Engineering Conference and ACM SIGSOFT International       */
/*  Symposium on the Foundations of Software Engineering                */
/*  (ESEC/FSE 99, Toulouse, Frankreich, September 1999), LNCS,          */
/*  Springer-Verlag, 1999, see                                          */
/*  http://nero.prakinf.tu-ilmenau.de/~czarn/esec99                     */
/*                                                                      */
/*  Copyright 1998-99 by Krzysztof Czarnecki and Ulrich W. Eisenecker   */
/*  E-mail: czarnecki@acm.org and ulrich.eisenecker@t-online.de         */
/*                                                                      */
/*  Please direct questions, bug reports, and contributions to the      */
/*  authors.                                                            */
/*                                                                      */
/*  THIS SOFTWARE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR          */
/*  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED      */
/*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
/*                                                                      */
/************************************************************************/

//NOTE:
// This code was tested with egcs1.1 and MS VC++ 5.0 service pack level 3.


namespace meta {

// IF implemented using member templates

namespace intimate
{ //selector template selecting ThenType
  struct SelectThen 
  { template<class ThenType, class ElseType>
    struct Result
    { typedef ThenType RET; };
  }; 

  //selector template selecting ElseType
  struct SelectElse
  { template<class ThenType, class ElseType>
    struct Result
    { typedef ElseType RET; };
  };

  //choose selector template depending on condition
  template<bool condition>
  struct ChooseSelector
  { typedef SelectThen RET; };

  template<>
  struct ChooseSelector<false>
  { typedef SelectElse RET; };

}; //end of namespace intimate


template<bool condition, class Then, class Else>
struct IF
{ typedef typename intimate::ChooseSelector<condition>::RET Selector;
  typedef typename Selector::Result<Then,Else>::RET RET;
};

/* The following is a simpler implementation of IF<>,
 * but it requires partial template specialization:
 *
 * template<bool condition, class Then, class Else>
 * struct IF
 * { typedef Then RET;
 * };
 *
 * //specialization for condition==false
 * template<class Then, class Else>
 * struct IF<false, Then, Else>
 * { typedef Else RET;
 * };
 *
 */


// CASE and SWITCH

const int nilValue = ~(~0u >> 1); //initialize with the smallest int
const int DEFAULT = nilValue+1;

struct NilCase 
{ enum {tag = nilValue};
  typedef NilCase RET;
}; 

template <int tag_,class Type_,class Next_ = NilCase>
struct CASE
{ enum {tag = tag_};
  typedef Type_ Type;
  typedef Next_ Next;
};


template <int tag,class Case>
struct SWITCH
{ typedef typename Case::Next NextCase;
  enum { caseTag = Case::tag,    
         nextTag = NextCase::tag,
         found   = (caseTag == tag ||
                    caseTag == DEFAULT) 
       };
  typedef typename IF<(nextTag == nilValue),
                      NilCase,
                      SWITCH<tag,NextCase> 
                     >::RET NextSwitch;
  typedef typename IF<(found != 0),
                      typename Case::Type,  
                      typename NextSwitch::RET
                     >::RET RET;
}; 

}; // namespace meta
